package concurrent;

import java.util.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * TODO 简单说明
 *
 * @author yangyang
 * @date 2017/7/27 9:39
 * @email kekecany@163.com
 */
public class GreenhouseScheduler {

    private static volatile boolean light = false;
    private static volatile boolean water = false;
    private String thermostat = "Day";

    public synchronized String getThermostat() {
        return thermostat;
    }

    private synchronized void setThermostat(String thermostat) {
        this.thermostat = thermostat;
    }

    private ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(10);

    private void schedule(Runnable event, long delay) {
        scheduler.schedule(event, delay, TimeUnit.MILLISECONDS);
    }

    private void repeat(Runnable event, long initialDelay, long period) {
        scheduler.scheduleAtFixedRate(event, initialDelay, period, TimeUnit.MILLISECONDS);
    }


    class LightOn implements Runnable {
        @Override
        public void run() {
            System.out.println("Turning on lights");
            light = true;
        }

        @Override
        public String toString() {
            return "light on";
        }
    }

    class LightOff implements Runnable {
        @Override
        public void run() {
            System.out.println("Turning off lights");
            light = false;
        }

        @Override
        public String toString() {
            return "light off";
        }
    }

    class WaterOn implements Runnable {
        @Override
        public void run() {
            System.out.println("Turning greenhouse water on");
            water = true;
        }

        @Override
        public String toString() {
            return "water on";
        }
    }

    class WaterOff implements Runnable {
        @Override
        public void run() {
            System.out.println("Turning greenhouse water off");
            water = false;
        }

        @Override
        public String toString() {
            return "water off";
        }
    }

    class ThermostatNight implements Runnable {
        @Override
        public void run() {
            System.out.println("Thermostat to night setting");
            setThermostat("Night");
        }

        @Override
        public String toString() {
            return "night";
        }
    }

    class ThermostatDay implements Runnable {
        @Override
        public void run() {
            System.out.println("Thermostat to day setting");
            setThermostat("Day");
        }

        @Override
        public String toString() {
            return "day";
        }
    }

    class Bell implements Runnable {
        @Override
        public void run() {
            System.out.println("bing!~");
            while (true) {
                System.out.println();
            }
        }

        @Override
        public String toString() {
            return "bell";
        }
    }

    class Terminate implements Runnable {
        @Override
        public void run() {
            System.out.println("Terminating");
            List<Runnable> list = scheduler.shutdownNow();
            System.out.println(list);
            // must start a separate task to do this job
            // since the scheduler has been shut down
            /*try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }*/
            new Thread(() -> {
                for (DataPoint dataPoint : data) {
                    System.out.println(dataPoint);
                }
            }).start();
            /*while (true) {

            }*/
        }

        @Override
        public String toString() {
            return "terminate";
        }
    }

    // new feature: data collection
    static class DataPoint {
        final Calendar time;
        final float temperature;
        final float humidity;

        DataPoint(Calendar time, float temperature, float humidity) {
            this.time = time;
            this.temperature = temperature;
            this.humidity = humidity;
        }

        @Override
        public String toString() {
            return time.getTime() + String.format(" temperature: %1$.1f humidity: %2$.2f", temperature, humidity);
        }
    }

    private Calendar lastTime = Calendar.getInstance();

    {
        lastTime.set(Calendar.MINUTE, 30);
        lastTime.set(Calendar.SECOND, 0);
    }

    private float lastTemp = 65.0f;
    private int tempDirection = +1;
    private float lastHumidity = 50.0f;
    private int humidityDirection = +1;

    private Random random = new Random(47);
    private List<DataPoint> data = Collections.synchronizedList(new ArrayList<>());

    class CollectData implements Runnable {
        @Override
        public void run() {
            System.out.println("Collecting data");
            synchronized (GreenhouseScheduler.this) {
                lastTime.set(Calendar.MINUTE, lastTime.get(Calendar.MINUTE) + 30);
                if (random.nextInt(5) == 4) {
                    tempDirection = -tempDirection;
                }
                lastTemp = lastTemp + tempDirection * (1.0f + random.nextFloat());
                if (random.nextInt(5) == 4) {
                    humidityDirection = -humidityDirection;
                }
                lastHumidity = lastHumidity + humidityDirection * random.nextFloat();
                data.add(new DataPoint((Calendar) lastTime.clone(), lastTemp, lastHumidity));
            }
        }
        @Override
        public String toString() {
            return "collect data";
        }
    }

    public static void main(String[] args) {
        GreenhouseScheduler greenhouseScheduler = new GreenhouseScheduler();
        greenhouseScheduler.schedule(greenhouseScheduler.new Terminate(), 5000);
        greenhouseScheduler.repeat(greenhouseScheduler.new Bell(), 0, 1000);
        greenhouseScheduler.repeat(greenhouseScheduler.new ThermostatNight(), 0, 2000);
        greenhouseScheduler.repeat(greenhouseScheduler.new LightOn(), 0, 200);
        greenhouseScheduler.repeat(greenhouseScheduler.new LightOff(), 0, 400);
        greenhouseScheduler.repeat(greenhouseScheduler.new WaterOn(), 0, 600);
        greenhouseScheduler.repeat(greenhouseScheduler.new WaterOff(), 0, 800);
        greenhouseScheduler.repeat(greenhouseScheduler.new ThermostatDay(), 0, 1400);
        greenhouseScheduler.repeat(greenhouseScheduler.new CollectData(), 500, 500);

    }
}
